#include <Core/Field.h>
#include <DataTypes/DataTypeDate.h>
#include <Functions/FunctionFactory.h>
#include <Functions/IFunction.h>
#include <Common/DateLUT.h>
#include <Common/DateLUTImpl.h>


namespace DB
{
namespace
{

class ExecutableFunctionToday : public IExecutableFunction
{
public:
    explicit ExecutableFunctionToday(time_t time_) : day_value(time_) {}

    String getName() const override { return "today"; }

    ColumnPtr executeImpl(const ColumnsWithTypeAndName &, const DataTypePtr &, size_t input_rows_count) const override
    {
        return DataTypeDate().createColumnConst(input_rows_count, day_value);
    }

private:
    DayNum day_value;
};

class FunctionBaseToday : public IFunctionBase
{
public:
    explicit FunctionBaseToday(DayNum day_value_) : day_value(day_value_), return_type(std::make_shared<DataTypeDate>()) {}

    String getName() const override { return "today"; }

    const DataTypes & getArgumentTypes() const override
    {
        static const DataTypes argument_types;
        return argument_types;
    }

    const DataTypePtr & getResultType() const override
    {
        return return_type;
    }

    ExecutableFunctionPtr prepare(const ColumnsWithTypeAndName &) const override
    {
        return std::make_unique<ExecutableFunctionToday>(day_value);
    }

    bool isDeterministic() const override { return false; }
    bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }

private:
    DayNum day_value;
    DataTypePtr return_type;
};

class TodayOverloadResolver : public IFunctionOverloadResolver
{
public:
    static constexpr auto name = "today";

    String getName() const override { return name; }

    bool isDeterministic() const override { return false; }

    size_t getNumberOfArguments() const override { return 0; }

    static FunctionOverloadResolverPtr create(ContextPtr) { return std::make_unique<TodayOverloadResolver>(); }

    DataTypePtr getReturnTypeImpl(const DataTypes &) const override { return std::make_shared<DataTypeDate>(); }

    FunctionBasePtr buildImpl(const ColumnsWithTypeAndName &, const DataTypePtr &) const override
    {
        return std::make_unique<FunctionBaseToday>(DayNum(DateLUT::instance().toDayNum(time(nullptr)).toUnderType()));
    }
};

}

REGISTER_FUNCTION(Today)
{
    FunctionDocumentation::Description description = "Returns the current date at moment of query analysis. Same as `toDate(now())`.";
    FunctionDocumentation::Syntax syntax = "today()";
    FunctionDocumentation::Arguments arguments = {};
    FunctionDocumentation::ReturnedValue returned_value = {"Returns the current date", {"Date"}};
    FunctionDocumentation::Examples example = {
        {
            "Usage example",
            "SELECT today() AS today, curdate() AS curdate, current_date() AS current_date FORMAT Pretty",
R"(
┏━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━┓
┃      today ┃    curdate ┃ current_date ┃
┡━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━┩
│ 2025-03-03 │ 2025-03-03 │   2025-03-03 │
└────────────┴────────────┴──────────────┘
)"
        }
    };
    FunctionDocumentation::IntroducedIn introduced_in = {1, 1};
    FunctionDocumentation::Category category = FunctionDocumentation::Category::DateAndTime;
    FunctionDocumentation documentation = {description, syntax, arguments, returned_value, example, introduced_in, category};

    factory.registerFunction<TodayOverloadResolver>(documentation);
    factory.registerAlias("current_date", TodayOverloadResolver::name, FunctionFactory::Case::Insensitive);
    factory.registerAlias("curdate", TodayOverloadResolver::name, FunctionFactory::Case::Insensitive);
}

}
